package com.lightspring.beans.factory.support;

import com.lightspring.beans.BeansException;
import com.lightspring.beans.factory.BeanFactory;
import com.lightspring.beans.factory.ConfigurableBeanFactory;
import com.lightspring.beans.factory.FactoryBean;
import com.lightspring.beans.factory.config.BeanDefinition;
import com.lightspring.utils.ClassUtils;


/**
 * BeanFactory抽象类实现
 * @author 毅航
 * @date 2024/5/19 22:50
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport
        implements ConfigurableBeanFactory {

    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();



    public AbstractBeanFactory() {
    }

    @Override
    public Object getBean(String beanName) throws BeansException {
        return doGetBean(beanName,null);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) getBean(name);
    }


    private <T> T doGetBean(final String beanName, final Object[] args) {
        Object sharedInstance  = getSingleton(beanName);
        if (sharedInstance != null) {
            // 如果缓存的bean类型为FactoryBean需要额外处理
            return (T) getObjectForBeanInstance(sharedInstance,beanName);
        }
        BeanDefinition beanDefinition = getBeanDefinition(beanName);
        Object bean = createBean(beanName, beanDefinition, args);
        return (T) getObjectForBeanInstance(bean, beanName);
    }


    @Override
    public void registerBeanDefinition(String beanName, Object bd) {

    }

    @Override
    public BeanFactory getParentBeanFactory() {
        return null;
    }

    @Override
    public boolean containsLocalBean(String name) {
        return false;
    }


    @Override
    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;


    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) ;


    /**
     * 获取FactoryBean实例
     * @param sharedInstance
     * @param beanName
     * @return
     */
    private Object getObjectForBeanInstance(Object sharedInstance, String beanName) {

        if (sharedInstance instanceof FactoryBean) {
            try {
                return ((FactoryBean) sharedInstance).getObject();
            } catch (Exception e) {
                throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
            }
        } else {
            return sharedInstance;
        }
    }

}
